➔ parseDateTimeInternal   B
last analyzed

Complexity

Conditions 3
Paths 2

Size

Total Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 25
c 0
b 0
f 0
cc 3
nc 2
nop 5
rs 8.8571
1
/*! jQuery Timepicker Addon - v1.6.3 - 2016-04-20
2
* http://trentrichardson.com/examples/timepicker
3
* Copyright (c) 2016 Trent Richardson; Licensed MIT */
4
(function (factory) {
5
	if (typeof define === 'function' && define.amd) {
0 ignored issues
show
Bug introduced by
The variable define seems to be never declared. If this is a global, consider adding a /** global: define */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
6
		define(['jquery', 'jquery-ui'], factory);
7
	} else {
8
		factory(jQuery);
9
	}
10
}(function ($) {
11
12
	/*
13
	* Lets not redefine timepicker, Prevent "Uncaught RangeError: Maximum call stack size exceeded"
14
	*/
15
	$.ui.timepicker = $.ui.timepicker || {};
16
	if ($.ui.timepicker.version) {
17
		return;
18
	}
19
20
	/*
21
	* Extend jQueryUI, get it started with our version number
22
	*/
23
	$.extend($.ui, {
24
		timepicker: {
25
			version: "1.6.3"
26
		}
27
	});
28
29
	/*
30
	* Timepicker manager.
31
	* Use the singleton instance of this class, $.timepicker, to interact with the time picker.
32
	* Settings for (groups of) time pickers are maintained in an instance object,
33
	* allowing multiple different settings on the same page.
34
	*/
35
	var Timepicker = function () {
36
		this.regional = []; // Available regional settings, indexed by language code
37
		this.regional[''] = { // Default regional settings
38
			currentText: 'Now',
39
			closeText: 'Done',
40
			amNames: ['AM', 'A'],
41
			pmNames: ['PM', 'P'],
42
			timeFormat: 'HH:mm',
43
			timeSuffix: '',
44
			timeOnlyTitle: 'Choose Time',
45
			timeText: 'Time',
46
			hourText: 'Hour',
47
			minuteText: 'Minute',
48
			secondText: 'Second',
49
			millisecText: 'Millisecond',
50
			microsecText: 'Microsecond',
51
			timezoneText: 'Time Zone',
52
			isRTL: false
53
		};
54
		this._defaults = { // Global defaults for all the datetime picker instances
55
			showButtonPanel: true,
56
			timeOnly: false,
57
			timeOnlyShowDate: false,
58
			showHour: null,
59
			showMinute: null,
60
			showSecond: null,
61
			showMillisec: null,
62
			showMicrosec: null,
63
			showTimezone: null,
64
			showTime: true,
65
			stepHour: 1,
66
			stepMinute: 1,
67
			stepSecond: 1,
68
			stepMillisec: 1,
69
			stepMicrosec: 1,
70
			hour: 0,
71
			minute: 0,
72
			second: 0,
73
			millisec: 0,
74
			microsec: 0,
75
			timezone: null,
76
			hourMin: 0,
77
			minuteMin: 0,
78
			secondMin: 0,
79
			millisecMin: 0,
80
			microsecMin: 0,
81
			hourMax: 23,
82
			minuteMax: 59,
83
			secondMax: 59,
84
			millisecMax: 999,
85
			microsecMax: 999,
86
			minDateTime: null,
87
			maxDateTime: null,
88
			maxTime: null,
89
			minTime: null,
90
			onSelect: null,
91
			hourGrid: 0,
92
			minuteGrid: 0,
93
			secondGrid: 0,
94
			millisecGrid: 0,
95
			microsecGrid: 0,
96
			alwaysSetTime: true,
97
			separator: ' ',
98
			altFieldTimeOnly: true,
99
			altTimeFormat: null,
100
			altSeparator: null,
101
			altTimeSuffix: null,
102
			altRedirectFocus: true,
103
			pickerTimeFormat: null,
104
			pickerTimeSuffix: null,
105
			showTimepicker: true,
106
			timezoneList: null,
107
			addSliderAccess: false,
108
			sliderAccessArgs: null,
109
			controlType: 'slider',
110
			oneLine: false,
111
			defaultValue: null,
112
			parse: 'strict',
113
			afterInject: null
114
		};
115
		$.extend(this._defaults, this.regional['']);
116
	};
117
118
	$.extend(Timepicker.prototype, {
119
		$input: null,
120
		$altInput: null,
121
		$timeObj: null,
122
		inst: null,
123
		hour_slider: null,
124
		minute_slider: null,
125
		second_slider: null,
126
		millisec_slider: null,
127
		microsec_slider: null,
128
		timezone_select: null,
129
		maxTime: null,
130
		minTime: null,
131
		hour: 0,
132
		minute: 0,
133
		second: 0,
134
		millisec: 0,
135
		microsec: 0,
136
		timezone: null,
137
		hourMinOriginal: null,
138
		minuteMinOriginal: null,
139
		secondMinOriginal: null,
140
		millisecMinOriginal: null,
141
		microsecMinOriginal: null,
142
		hourMaxOriginal: null,
143
		minuteMaxOriginal: null,
144
		secondMaxOriginal: null,
145
		millisecMaxOriginal: null,
146
		microsecMaxOriginal: null,
147
		ampm: '',
148
		formattedDate: '',
149
		formattedTime: '',
150
		formattedDateTime: '',
151
		timezoneList: null,
152
		units: ['hour', 'minute', 'second', 'millisec', 'microsec'],
153
		support: {},
154
		control: null,
155
156
		/*
157
		* Override the default settings for all instances of the time picker.
158
		* @param  {Object} settings  object - the new settings to use as defaults (anonymous object)
159
		* @return {Object} the manager object
160
		*/
161
		setDefaults: function (settings) {
162
			extendRemove(this._defaults, settings || {});
163
			return this;
164
		},
165
166
		/*
167
		* Create a new Timepicker instance
168
		*/
169
		_newInst: function ($input, opts) {
170
			var tp_inst = new Timepicker(),
171
				inlineSettings = {},
172
				fns = {},
173
				overrides, i;
174
175
			for (var attrName in this._defaults) {
176
				if (this._defaults.hasOwnProperty(attrName)) {
177
					var attrValue = $input.attr('time:' + attrName);
178
					if (attrValue) {
179
						try {
180
							inlineSettings[attrName] = eval(attrValue);
0 ignored issues
show
Security Performance introduced by
Calls to eval are slow and potentially dangerous, especially on untrusted code. Please consider whether there is another way to achieve your goal.
Loading history...
181
						} catch (err) {
182
							inlineSettings[attrName] = attrValue;
183
						}
184
					}
185
				}
186
			}
187
188
			overrides = {
189
				beforeShow: function (input, dp_inst) {
190
					if ($.isFunction(tp_inst._defaults.evnts.beforeShow)) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if $.isFunction(tp_inst._defaults.evnts.beforeShow) is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
191
						return tp_inst._defaults.evnts.beforeShow.call($input[0], input, dp_inst, tp_inst);
192
					}
193
				},
194
				onChangeMonthYear: function (year, month, dp_inst) {
195
					// Update the time as well : this prevents the time from disappearing from the $input field.
196
					// tp_inst._updateDateTime(dp_inst);
197
					if ($.isFunction(tp_inst._defaults.evnts.onChangeMonthYear)) {
198
						tp_inst._defaults.evnts.onChangeMonthYear.call($input[0], year, month, dp_inst, tp_inst);
199
					}
200
				},
201
				onClose: function (dateText, dp_inst) {
202
					if (tp_inst.timeDefined === true && $input.val() !== '') {
203
						tp_inst._updateDateTime(dp_inst);
204
					}
205
					if ($.isFunction(tp_inst._defaults.evnts.onClose)) {
206
						tp_inst._defaults.evnts.onClose.call($input[0], dateText, dp_inst, tp_inst);
207
					}
208
				}
209
			};
210
			for (i in overrides) {
211
				if (overrides.hasOwnProperty(i)) {
212
					fns[i] = opts[i] || this._defaults[i] || null;
213
				}
214
			}
215
216
			tp_inst._defaults = $.extend({}, this._defaults, inlineSettings, opts, overrides, {
217
				evnts: fns,
218
				timepicker: tp_inst // add timepicker as a property of datepicker: $.datepicker._get(dp_inst, 'timepicker');
219
			});
220
			tp_inst.amNames = $.map(tp_inst._defaults.amNames, function (val) {
221
				return val.toUpperCase();
222
			});
223
			tp_inst.pmNames = $.map(tp_inst._defaults.pmNames, function (val) {
224
				return val.toUpperCase();
225
			});
226
227
			// detect which units are supported
228
			tp_inst.support = detectSupport(
229
					tp_inst._defaults.timeFormat +
230
					(tp_inst._defaults.pickerTimeFormat ? tp_inst._defaults.pickerTimeFormat : '') +
231
					(tp_inst._defaults.altTimeFormat ? tp_inst._defaults.altTimeFormat : ''));
232
233
			// controlType is string - key to our this._controls
234
			if (typeof(tp_inst._defaults.controlType) === 'string') {
235
				if (tp_inst._defaults.controlType === 'slider' && typeof($.ui.slider) === 'undefined') {
236
					tp_inst._defaults.controlType = 'select';
237
				}
238
				tp_inst.control = tp_inst._controls[tp_inst._defaults.controlType];
239
			}
240
			// controlType is an object and must implement create, options, value methods
241
			else {
242
				tp_inst.control = tp_inst._defaults.controlType;
243
			}
244
245
			// prep the timezone options
246
			var timezoneList = [-720, -660, -600, -570, -540, -480, -420, -360, -300, -270, -240, -210, -180, -120, -60,
247
					0, 60, 120, 180, 210, 240, 270, 300, 330, 345, 360, 390, 420, 480, 525, 540, 570, 600, 630, 660, 690, 720, 765, 780, 840];
248
			if (tp_inst._defaults.timezoneList !== null) {
249
				timezoneList = tp_inst._defaults.timezoneList;
250
			}
251
			var tzl = timezoneList.length, tzi = 0, tzv = null;
0 ignored issues
show
Unused Code introduced by
The assignment to tzv seems to be never used. If you intend to free memory here, this is not necessary since the variable leaves the scope anyway.
Loading history...
252
			if (tzl > 0 && typeof timezoneList[0] !== 'object') {
253
				for (; tzi < tzl; tzi++) {
254
					tzv = timezoneList[tzi];
255
					timezoneList[tzi] = { value: tzv, label: $.timepicker.timezoneOffsetString(tzv, tp_inst.support.iso8601) };
256
				}
257
			}
258
			tp_inst._defaults.timezoneList = timezoneList;
259
260
			// set the default units
261
			tp_inst.timezone = tp_inst._defaults.timezone !== null ? $.timepicker.timezoneOffsetNumber(tp_inst._defaults.timezone) :
262
							((new Date()).getTimezoneOffset() * -1);
263
			tp_inst.hour = tp_inst._defaults.hour < tp_inst._defaults.hourMin ? tp_inst._defaults.hourMin :
264
							tp_inst._defaults.hour > tp_inst._defaults.hourMax ? tp_inst._defaults.hourMax : tp_inst._defaults.hour;
265
			tp_inst.minute = tp_inst._defaults.minute < tp_inst._defaults.minuteMin ? tp_inst._defaults.minuteMin :
266
							tp_inst._defaults.minute > tp_inst._defaults.minuteMax ? tp_inst._defaults.minuteMax : tp_inst._defaults.minute;
267
			tp_inst.second = tp_inst._defaults.second < tp_inst._defaults.secondMin ? tp_inst._defaults.secondMin :
268
							tp_inst._defaults.second > tp_inst._defaults.secondMax ? tp_inst._defaults.secondMax : tp_inst._defaults.second;
269
			tp_inst.millisec = tp_inst._defaults.millisec < tp_inst._defaults.millisecMin ? tp_inst._defaults.millisecMin :
270
							tp_inst._defaults.millisec > tp_inst._defaults.millisecMax ? tp_inst._defaults.millisecMax : tp_inst._defaults.millisec;
271
			tp_inst.microsec = tp_inst._defaults.microsec < tp_inst._defaults.microsecMin ? tp_inst._defaults.microsecMin :
272
							tp_inst._defaults.microsec > tp_inst._defaults.microsecMax ? tp_inst._defaults.microsecMax : tp_inst._defaults.microsec;
273
			tp_inst.ampm = '';
274
			tp_inst.$input = $input;
275
276
			if (tp_inst._defaults.altField) {
277
				tp_inst.$altInput = $(tp_inst._defaults.altField);
278
				if (tp_inst._defaults.altRedirectFocus === true) {
279
					tp_inst.$altInput.css({
280
						cursor: 'pointer'
281
					}).focus(function () {
282
						$input.trigger("focus");
283
					});
284
				}
285
			}
286
287
			if (tp_inst._defaults.minDate === 0 || tp_inst._defaults.minDateTime === 0) {
288
				tp_inst._defaults.minDate = new Date();
289
			}
290
			if (tp_inst._defaults.maxDate === 0 || tp_inst._defaults.maxDateTime === 0) {
291
				tp_inst._defaults.maxDate = new Date();
292
			}
293
294
			// datepicker needs minDate/maxDate, timepicker needs minDateTime/maxDateTime..
295
			if (tp_inst._defaults.minDate !== undefined && tp_inst._defaults.minDate instanceof Date) {
296
				tp_inst._defaults.minDateTime = new Date(tp_inst._defaults.minDate.getTime());
297
			}
298
			if (tp_inst._defaults.minDateTime !== undefined && tp_inst._defaults.minDateTime instanceof Date) {
299
				tp_inst._defaults.minDate = new Date(tp_inst._defaults.minDateTime.getTime());
300
			}
301
			if (tp_inst._defaults.maxDate !== undefined && tp_inst._defaults.maxDate instanceof Date) {
302
				tp_inst._defaults.maxDateTime = new Date(tp_inst._defaults.maxDate.getTime());
303
			}
304
			if (tp_inst._defaults.maxDateTime !== undefined && tp_inst._defaults.maxDateTime instanceof Date) {
305
				tp_inst._defaults.maxDate = new Date(tp_inst._defaults.maxDateTime.getTime());
306
			}
307
			tp_inst.$input.bind('focus', function () {
308
				tp_inst._onFocus();
309
			});
310
311
			return tp_inst;
312
		},
313
314
		/*
315
		* add our sliders to the calendar
316
		*/
317
		_addTimePicker: function (dp_inst) {
318
			var currDT = $.trim((this.$altInput && this._defaults.altFieldTimeOnly) ? this.$input.val() + ' ' + this.$altInput.val() : this.$input.val());
319
320
			this.timeDefined = this._parseTime(currDT);
321
			this._limitMinMaxDateTime(dp_inst, false);
322
			this._injectTimePicker();
323
			this._afterInject();
324
		},
325
326
		/*
327
		* parse the time string from input value or _setTime
328
		*/
329
		_parseTime: function (timeString, withDate) {
330
			if (!this.inst) {
331
				this.inst = $.datepicker._getInst(this.$input[0]);
332
			}
333
334
			if (withDate || !this._defaults.timeOnly) {
335
				var dp_dateFormat = $.datepicker._get(this.inst, 'dateFormat');
336
				try {
337
					var parseRes = parseDateTimeInternal(dp_dateFormat, this._defaults.timeFormat, timeString, $.datepicker._getFormatConfig(this.inst), this._defaults);
338
					if (!parseRes.timeObj) {
339
						return false;
340
					}
341
					$.extend(this, parseRes.timeObj);
342
				} catch (err) {
343
					$.timepicker.log("Error parsing the date/time string: " + err +
344
									"\ndate/time string = " + timeString +
345
									"\ntimeFormat = " + this._defaults.timeFormat +
346
									"\ndateFormat = " + dp_dateFormat);
347
					return false;
348
				}
349
				return true;
350
			} else {
351
				var timeObj = $.datepicker.parseTime(this._defaults.timeFormat, timeString, this._defaults);
352
				if (!timeObj) {
353
					return false;
354
				}
355
				$.extend(this, timeObj);
356
				return true;
357
			}
358
		},
359
360
		/*
361
		* Handle callback option after injecting timepicker
362
		*/
363
		_afterInject: function() {
364
			var o = this.inst.settings;
365
			if ($.isFunction(o.afterInject)) {
366
				o.afterInject.call(this);
367
			}
368
		},
369
370
		/*
371
		* generate and inject html for timepicker into ui datepicker
372
		*/
373
		_injectTimePicker: function () {
374
			var $dp = this.inst.dpDiv,
375
				o = this.inst.settings,
376
				tp_inst = this,
377
				litem = '',
378
				uitem = '',
379
				show = null,
0 ignored issues
show
Unused Code introduced by
The assignment to show seems to be never used. If you intend to free memory here, this is not necessary since the variable leaves the scope anyway.
Loading history...
380
				max = {},
381
				gridSize = {},
382
				size = null,
0 ignored issues
show
Unused Code introduced by
The assignment to size seems to be never used. If you intend to free memory here, this is not necessary since the variable leaves the scope anyway.
Loading history...
383
				i = 0,
384
				l = 0;
385
386
			// Prevent displaying twice
387
			if ($dp.find("div.ui-timepicker-div").length === 0 && o.showTimepicker) {
388
				var noDisplay = ' ui_tpicker_unit_hide',
389
					html = '<div class="ui-timepicker-div' + (o.isRTL ? ' ui-timepicker-rtl' : '') + (o.oneLine && o.controlType === 'select' ? ' ui-timepicker-oneLine' : '') + '"><dl>' + '<dt class="ui_tpicker_time_label' + ((o.showTime) ? '' : noDisplay) + '">' + o.timeText + '</dt>' +
390
								'<dd class="ui_tpicker_time '+ ((o.showTime) ? '' : noDisplay) + '"><input class="ui_tpicker_time_input" ' + (o.timeInput ? '' : 'disabled') + '/></dd>';
391
392
				// Create the markup
393
				for (i = 0, l = this.units.length; i < l; i++) {
394
					litem = this.units[i];
395
					uitem = litem.substr(0, 1).toUpperCase() + litem.substr(1);
396
					show = o['show' + uitem] !== null ? o['show' + uitem] : this.support[litem];
397
398
					// Added by Peter Medeiros:
399
					// - Figure out what the hour/minute/second max should be based on the step values.
400
					// - Example: if stepMinute is 15, then minMax is 45.
401
					max[litem] = parseInt((o[litem + 'Max'] - ((o[litem + 'Max'] - o[litem + 'Min']) % o['step' + uitem])), 10);
402
					gridSize[litem] = 0;
403
404
					html += '<dt class="ui_tpicker_' + litem + '_label' + (show ? '' : noDisplay) + '">' + o[litem + 'Text'] + '</dt>' +
405
								'<dd class="ui_tpicker_' + litem + (show ? '' : noDisplay) + '"><div class="ui_tpicker_' + litem + '_slider' + (show ? '' : noDisplay) + '"></div>';
406
407
					if (show && o[litem + 'Grid'] > 0) {
408
						html += '<div style="padding-left: 1px"><table class="ui-tpicker-grid-label"><tr>';
409
410
						if (litem === 'hour') {
411
							for (var h = o[litem + 'Min']; h <= max[litem]; h += parseInt(o[litem + 'Grid'], 10)) {
412
								gridSize[litem]++;
413
								var tmph = $.datepicker.formatTime(this.support.ampm ? 'hht' : 'HH', {hour: h}, o);
414
								html += '<td data-for="' + litem + '">' + tmph + '</td>';
415
							}
416
						}
417
						else {
418
							for (var m = o[litem + 'Min']; m <= max[litem]; m += parseInt(o[litem + 'Grid'], 10)) {
419
								gridSize[litem]++;
420
								html += '<td data-for="' + litem + '">' + ((m < 10) ? '0' : '') + m + '</td>';
421
							}
422
						}
423
424
						html += '</tr></table></div>';
425
					}
426
					html += '</dd>';
427
				}
428
429
				// Timezone
430
				var showTz = o.showTimezone !== null ? o.showTimezone : this.support.timezone;
431
				html += '<dt class="ui_tpicker_timezone_label' + (showTz ? '' : noDisplay) + '">' + o.timezoneText + '</dt>';
432
				html += '<dd class="ui_tpicker_timezone' + (showTz ? '' : noDisplay) + '"></dd>';
433
434
				// Create the elements from string
435
				html += '</dl></div>';
436
				var $tp = $(html);
437
438
				// if we only want time picker...
439
				if (o.timeOnly === true) {
440
					$tp.prepend('<div class="ui-widget-header ui-helper-clearfix ui-corner-all">' + '<div class="ui-datepicker-title">' + o.timeOnlyTitle + '</div>' + '</div>');
441
					$dp.find('.ui-datepicker-header, .ui-datepicker-calendar').hide();
442
				}
443
444
				// add sliders, adjust grids, add events
445
				for (i = 0, l = tp_inst.units.length; i < l; i++) {
446
					litem = tp_inst.units[i];
447
					uitem = litem.substr(0, 1).toUpperCase() + litem.substr(1);
448
					show = o['show' + uitem] !== null ? o['show' + uitem] : this.support[litem];
449
450
					// add the slider
451
					tp_inst[litem + '_slider'] = tp_inst.control.create(tp_inst, $tp.find('.ui_tpicker_' + litem + '_slider'), litem, tp_inst[litem], o[litem + 'Min'], max[litem], o['step' + uitem]);
452
453
					// adjust the grid and add click event
454
					if (show && o[litem + 'Grid'] > 0) {
455
						size = 100 * gridSize[litem] * o[litem + 'Grid'] / (max[litem] - o[litem + 'Min']);
456
						$tp.find('.ui_tpicker_' + litem + ' table').css({
457
							width: size + "%",
458
							marginLeft: o.isRTL ? '0' : ((size / (-2 * gridSize[litem])) + "%"),
459
							marginRight: o.isRTL ? ((size / (-2 * gridSize[litem])) + "%") : '0',
460
							borderCollapse: 'collapse'
461
						}).find("td").click(function (e) {
0 ignored issues
show
Unused Code introduced by
The parameter e is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
462
								var $t = $(this),
463
									h = $t.html(),
464
									n = parseInt(h.replace(/[^0-9]/g), 10),
465
									ap = h.replace(/[^apm]/ig),
466
									f = $t.data('for'); // loses scope, so we use data-for
467
468
								if (f === 'hour') {
469
									if (ap.indexOf('p') !== -1 && n < 12) {
470
										n += 12;
471
									}
472
									else {
473
										if (ap.indexOf('a') !== -1 && n === 12) {
474
											n = 0;
475
										}
476
									}
477
								}
478
479
								tp_inst.control.value(tp_inst, tp_inst[f + '_slider'], litem, n);
0 ignored issues
show
Bug introduced by
The variable litem is changed as part of the for loop for example by tp_inst.units.i on line 446. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
480
481
								tp_inst._onTimeChange();
482
								tp_inst._onSelectHandler();
483
							}).css({
484
								cursor: 'pointer',
485
								width: (100 / gridSize[litem]) + '%',
486
								textAlign: 'center',
487
								overflow: 'hidden'
488
							});
489
					} // end if grid > 0
490
				} // end for loop
491
492
				// Add timezone options
493
				this.timezone_select = $tp.find('.ui_tpicker_timezone').append('<select></select>').find("select");
494
				$.fn.append.apply(this.timezone_select,
495
				$.map(o.timezoneList, function (val, idx) {
0 ignored issues
show
Unused Code introduced by
The parameter idx is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
496
					return $("<option />").val(typeof val === "object" ? val.value : val).text(typeof val === "object" ? val.label : val);
497
				}));
498
				if (typeof(this.timezone) !== "undefined" && this.timezone !== null && this.timezone !== "") {
499
					var local_timezone = (new Date(this.inst.selectedYear, this.inst.selectedMonth, this.inst.selectedDay, 12)).getTimezoneOffset() * -1;
500
					if (local_timezone === this.timezone) {
501
						selectLocalTimezone(tp_inst);
502
					} else {
503
						this.timezone_select.val(this.timezone);
504
					}
505
				} else {
506
					if (typeof(this.hour) !== "undefined" && this.hour !== null && this.hour !== "") {
507
						this.timezone_select.val(o.timezone);
508
					} else {
509
						selectLocalTimezone(tp_inst);
510
					}
511
				}
512
				this.timezone_select.change(function () {
513
					tp_inst._onTimeChange();
514
					tp_inst._onSelectHandler();
515
					tp_inst._afterInject();
516
				});
517
				// End timezone options
518
519
				// inject timepicker into datepicker
520
				var $buttonPanel = $dp.find('.ui-datepicker-buttonpane');
521
				if ($buttonPanel.length) {
522
					$buttonPanel.before($tp);
523
				} else {
524
					$dp.append($tp);
525
				}
526
527
				this.$timeObj = $tp.find('.ui_tpicker_time_input');
528
				this.$timeObj.change(function () {
529
					var timeFormat = tp_inst.inst.settings.timeFormat;
530
					var parsedTime = $.datepicker.parseTime(timeFormat, this.value);
531
					var update = new Date();
532
					if (parsedTime) {
533
						update.setHours(parsedTime.hour);
534
						update.setMinutes(parsedTime.minute);
535
						update.setSeconds(parsedTime.second);
536
						$.datepicker._setTime(tp_inst.inst, update);
537
					} else {
538
						this.value = tp_inst.formattedTime;
539
						this.blur();
540
					}
541
				});
542
543
				if (this.inst !== null) {
544
					var timeDefined = this.timeDefined;
545
					this._onTimeChange();
546
					this.timeDefined = timeDefined;
547
				}
548
549
				// slideAccess integration: http://trentrichardson.com/2011/11/11/jquery-ui-sliders-and-touch-accessibility/
550
				if (this._defaults.addSliderAccess) {
551
					var sliderAccessArgs = this._defaults.sliderAccessArgs,
552
						rtl = this._defaults.isRTL;
553
					sliderAccessArgs.isRTL = rtl;
554
555
					setTimeout(function () { // fix for inline mode
556
						if ($tp.find('.ui-slider-access').length === 0) {
557
							$tp.find('.ui-slider:visible').sliderAccess(sliderAccessArgs);
558
559
							// fix any grids since sliders are shorter
560
							var sliderAccessWidth = $tp.find('.ui-slider-access:eq(0)').outerWidth(true);
561
							if (sliderAccessWidth) {
562
								$tp.find('table:visible').each(function () {
563
									var $g = $(this),
564
										oldWidth = $g.outerWidth(),
565
										oldMarginLeft = $g.css(rtl ? 'marginRight' : 'marginLeft').toString().replace('%', ''),
566
										newWidth = oldWidth - sliderAccessWidth,
567
										newMarginLeft = ((oldMarginLeft * newWidth) / oldWidth) + '%',
568
										css = { width: newWidth, marginRight: 0, marginLeft: 0 };
569
									css[rtl ? 'marginRight' : 'marginLeft'] = newMarginLeft;
570
									$g.css(css);
571
								});
572
							}
573
						}
574
					}, 10);
575
				}
576
				// end slideAccess integration
577
578
				tp_inst._limitMinMaxDateTime(this.inst, true);
579
			}
580
		},
581
582
		/*
583
		* This function tries to limit the ability to go outside the
584
		* min/max date range
585
		*/
586
		_limitMinMaxDateTime: function (dp_inst, adjustSliders) {
587
			var o = this._defaults,
588
				dp_date = new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay);
589
590
			if (!this._defaults.showTimepicker) {
591
				return;
592
			} // No time so nothing to check here
593
594
			if ($.datepicker._get(dp_inst, 'minDateTime') !== null && $.datepicker._get(dp_inst, 'minDateTime') !== undefined && dp_date) {
595
				var minDateTime = $.datepicker._get(dp_inst, 'minDateTime'),
596
					minDateTimeDate = new Date(minDateTime.getFullYear(), minDateTime.getMonth(), minDateTime.getDate(), 0, 0, 0, 0);
597
598
				if (this.hourMinOriginal === null || this.minuteMinOriginal === null || this.secondMinOriginal === null || this.millisecMinOriginal === null || this.microsecMinOriginal === null) {
599
					this.hourMinOriginal = o.hourMin;
600
					this.minuteMinOriginal = o.minuteMin;
601
					this.secondMinOriginal = o.secondMin;
602
					this.millisecMinOriginal = o.millisecMin;
603
					this.microsecMinOriginal = o.microsecMin;
604
				}
605
606
				if (dp_inst.settings.timeOnly || minDateTimeDate.getTime() === dp_date.getTime()) {
607
					this._defaults.hourMin = minDateTime.getHours();
608
					if (this.hour <= this._defaults.hourMin) {
609
						this.hour = this._defaults.hourMin;
610
						this._defaults.minuteMin = minDateTime.getMinutes();
611
						if (this.minute <= this._defaults.minuteMin) {
612
							this.minute = this._defaults.minuteMin;
613
							this._defaults.secondMin = minDateTime.getSeconds();
614
							if (this.second <= this._defaults.secondMin) {
615
								this.second = this._defaults.secondMin;
616
								this._defaults.millisecMin = minDateTime.getMilliseconds();
617
								if (this.millisec <= this._defaults.millisecMin) {
618
									this.millisec = this._defaults.millisecMin;
619
									this._defaults.microsecMin = minDateTime.getMicroseconds();
620
								} else {
621
									if (this.microsec < this._defaults.microsecMin) {
622
										this.microsec = this._defaults.microsecMin;
623
									}
624
									this._defaults.microsecMin = this.microsecMinOriginal;
625
								}
626
							} else {
627
								this._defaults.millisecMin = this.millisecMinOriginal;
628
								this._defaults.microsecMin = this.microsecMinOriginal;
629
							}
630
						} else {
631
							this._defaults.secondMin = this.secondMinOriginal;
632
							this._defaults.millisecMin = this.millisecMinOriginal;
633
							this._defaults.microsecMin = this.microsecMinOriginal;
634
						}
635
					} else {
636
						this._defaults.minuteMin = this.minuteMinOriginal;
637
						this._defaults.secondMin = this.secondMinOriginal;
638
						this._defaults.millisecMin = this.millisecMinOriginal;
639
						this._defaults.microsecMin = this.microsecMinOriginal;
640
					}
641
				} else {
642
					this._defaults.hourMin = this.hourMinOriginal;
643
					this._defaults.minuteMin = this.minuteMinOriginal;
644
					this._defaults.secondMin = this.secondMinOriginal;
645
					this._defaults.millisecMin = this.millisecMinOriginal;
646
					this._defaults.microsecMin = this.microsecMinOriginal;
647
				}
648
			}
649
650
			if ($.datepicker._get(dp_inst, 'maxDateTime') !== null && $.datepicker._get(dp_inst, 'maxDateTime') !== undefined && dp_date) {
651
				var maxDateTime = $.datepicker._get(dp_inst, 'maxDateTime'),
652
					maxDateTimeDate = new Date(maxDateTime.getFullYear(), maxDateTime.getMonth(), maxDateTime.getDate(), 0, 0, 0, 0);
653
654
				if (this.hourMaxOriginal === null || this.minuteMaxOriginal === null || this.secondMaxOriginal === null || this.millisecMaxOriginal === null) {
655
					this.hourMaxOriginal = o.hourMax;
656
					this.minuteMaxOriginal = o.minuteMax;
657
					this.secondMaxOriginal = o.secondMax;
658
					this.millisecMaxOriginal = o.millisecMax;
659
					this.microsecMaxOriginal = o.microsecMax;
660
				}
661
662
				if (dp_inst.settings.timeOnly || maxDateTimeDate.getTime() === dp_date.getTime()) {
663
					this._defaults.hourMax = maxDateTime.getHours();
664
					if (this.hour >= this._defaults.hourMax) {
665
						this.hour = this._defaults.hourMax;
666
						this._defaults.minuteMax = maxDateTime.getMinutes();
667
						if (this.minute >= this._defaults.minuteMax) {
668
							this.minute = this._defaults.minuteMax;
669
							this._defaults.secondMax = maxDateTime.getSeconds();
670
							if (this.second >= this._defaults.secondMax) {
671
								this.second = this._defaults.secondMax;
672
								this._defaults.millisecMax = maxDateTime.getMilliseconds();
673
								if (this.millisec >= this._defaults.millisecMax) {
674
									this.millisec = this._defaults.millisecMax;
675
									this._defaults.microsecMax = maxDateTime.getMicroseconds();
676
								} else {
677
									if (this.microsec > this._defaults.microsecMax) {
678
										this.microsec = this._defaults.microsecMax;
679
									}
680
									this._defaults.microsecMax = this.microsecMaxOriginal;
681
								}
682
							} else {
683
								this._defaults.millisecMax = this.millisecMaxOriginal;
684
								this._defaults.microsecMax = this.microsecMaxOriginal;
685
							}
686
						} else {
687
							this._defaults.secondMax = this.secondMaxOriginal;
688
							this._defaults.millisecMax = this.millisecMaxOriginal;
689
							this._defaults.microsecMax = this.microsecMaxOriginal;
690
						}
691
					} else {
692
						this._defaults.minuteMax = this.minuteMaxOriginal;
693
						this._defaults.secondMax = this.secondMaxOriginal;
694
						this._defaults.millisecMax = this.millisecMaxOriginal;
695
						this._defaults.microsecMax = this.microsecMaxOriginal;
696
					}
697
				} else {
698
					this._defaults.hourMax = this.hourMaxOriginal;
699
					this._defaults.minuteMax = this.minuteMaxOriginal;
700
					this._defaults.secondMax = this.secondMaxOriginal;
701
					this._defaults.millisecMax = this.millisecMaxOriginal;
702
					this._defaults.microsecMax = this.microsecMaxOriginal;
703
				}
704
			}
705
706
			if (dp_inst.settings.minTime!==null) {
707
				var tempMinTime=new Date("01/01/1970 " + dp_inst.settings.minTime);
708
				if (this.hour<tempMinTime.getHours()) {
709
					this.hour=this._defaults.hourMin=tempMinTime.getHours();
710
					this.minute=this._defaults.minuteMin=tempMinTime.getMinutes();
711
				} else if (this.hour===tempMinTime.getHours() && this.minute<tempMinTime.getMinutes()) {
712
					this.minute=this._defaults.minuteMin=tempMinTime.getMinutes();
713
				} else {
714
					if (this._defaults.hourMin<tempMinTime.getHours()) {
715
						this._defaults.hourMin=tempMinTime.getHours();
716
						this._defaults.minuteMin=tempMinTime.getMinutes();
717
					} else if (this._defaults.hourMin===tempMinTime.getHours()===this.hour && this._defaults.minuteMin<tempMinTime.getMinutes()) {
718
						this._defaults.minuteMin=tempMinTime.getMinutes();
719
					} else {
720
						this._defaults.minuteMin=0;
721
					}
722
				}
723
			}
724
725
			if (dp_inst.settings.maxTime!==null) {
726
				var tempMaxTime=new Date("01/01/1970 " + dp_inst.settings.maxTime);
727
				if (this.hour>tempMaxTime.getHours()) {
728
					this.hour=this._defaults.hourMax=tempMaxTime.getHours();
729
					this.minute=this._defaults.minuteMax=tempMaxTime.getMinutes();
730
				} else if (this.hour===tempMaxTime.getHours() && this.minute>tempMaxTime.getMinutes()) {
731
					this.minute=this._defaults.minuteMax=tempMaxTime.getMinutes();
732
				} else {
733
					if (this._defaults.hourMax>tempMaxTime.getHours()) {
734
						this._defaults.hourMax=tempMaxTime.getHours();
735
						this._defaults.minuteMax=tempMaxTime.getMinutes();
736
					} else if (this._defaults.hourMax===tempMaxTime.getHours()===this.hour && this._defaults.minuteMax>tempMaxTime.getMinutes()) {
737
						this._defaults.minuteMax=tempMaxTime.getMinutes();
738
					} else {
739
						this._defaults.minuteMax=59;
740
					}
741
				}
742
			}
743
744
			if (adjustSliders !== undefined && adjustSliders === true) {
745
				var hourMax = parseInt((this._defaults.hourMax - ((this._defaults.hourMax - this._defaults.hourMin) % this._defaults.stepHour)), 10),
746
					minMax = parseInt((this._defaults.minuteMax - ((this._defaults.minuteMax - this._defaults.minuteMin) % this._defaults.stepMinute)), 10),
747
					secMax = parseInt((this._defaults.secondMax - ((this._defaults.secondMax - this._defaults.secondMin) % this._defaults.stepSecond)), 10),
748
					millisecMax = parseInt((this._defaults.millisecMax - ((this._defaults.millisecMax - this._defaults.millisecMin) % this._defaults.stepMillisec)), 10),
749
					microsecMax = parseInt((this._defaults.microsecMax - ((this._defaults.microsecMax - this._defaults.microsecMin) % this._defaults.stepMicrosec)), 10);
750
751
				if (this.hour_slider) {
752
					this.control.options(this, this.hour_slider, 'hour', { min: this._defaults.hourMin, max: hourMax, step: this._defaults.stepHour });
753
					this.control.value(this, this.hour_slider, 'hour', this.hour - (this.hour % this._defaults.stepHour));
754
				}
755
				if (this.minute_slider) {
756
					this.control.options(this, this.minute_slider, 'minute', { min: this._defaults.minuteMin, max: minMax, step: this._defaults.stepMinute });
757
					this.control.value(this, this.minute_slider, 'minute', this.minute - (this.minute % this._defaults.stepMinute));
758
				}
759
				if (this.second_slider) {
760
					this.control.options(this, this.second_slider, 'second', { min: this._defaults.secondMin, max: secMax, step: this._defaults.stepSecond });
761
					this.control.value(this, this.second_slider, 'second', this.second - (this.second % this._defaults.stepSecond));
762
				}
763
				if (this.millisec_slider) {
764
					this.control.options(this, this.millisec_slider, 'millisec', { min: this._defaults.millisecMin, max: millisecMax, step: this._defaults.stepMillisec });
765
					this.control.value(this, this.millisec_slider, 'millisec', this.millisec - (this.millisec % this._defaults.stepMillisec));
766
				}
767
				if (this.microsec_slider) {
768
					this.control.options(this, this.microsec_slider, 'microsec', { min: this._defaults.microsecMin, max: microsecMax, step: this._defaults.stepMicrosec });
769
					this.control.value(this, this.microsec_slider, 'microsec', this.microsec - (this.microsec % this._defaults.stepMicrosec));
770
				}
771
			}
772
773
		},
774
775
		/*
776
		* when a slider moves, set the internal time...
777
		* on time change is also called when the time is updated in the text field
778
		*/
779
		_onTimeChange: function () {
780
			if (!this._defaults.showTimepicker) {
781
                                return;
782
			}
783
			var hour = (this.hour_slider) ? this.control.value(this, this.hour_slider, 'hour') : false,
784
				minute = (this.minute_slider) ? this.control.value(this, this.minute_slider, 'minute') : false,
785
				second = (this.second_slider) ? this.control.value(this, this.second_slider, 'second') : false,
786
				millisec = (this.millisec_slider) ? this.control.value(this, this.millisec_slider, 'millisec') : false,
787
				microsec = (this.microsec_slider) ? this.control.value(this, this.microsec_slider, 'microsec') : false,
788
				timezone = (this.timezone_select) ? this.timezone_select.val() : false,
789
				o = this._defaults,
790
				pickerTimeFormat = o.pickerTimeFormat || o.timeFormat,
791
				pickerTimeSuffix = o.pickerTimeSuffix || o.timeSuffix;
792
793
			if (typeof(hour) === 'object') {
794
				hour = false;
795
			}
796
			if (typeof(minute) === 'object') {
797
				minute = false;
798
			}
799
			if (typeof(second) === 'object') {
800
				second = false;
801
			}
802
			if (typeof(millisec) === 'object') {
803
				millisec = false;
804
			}
805
			if (typeof(microsec) === 'object') {
806
				microsec = false;
807
			}
808
			if (typeof(timezone) === 'object') {
809
				timezone = false;
810
			}
811
812
			if (hour !== false) {
813
				hour = parseInt(hour, 10);
814
			}
815
			if (minute !== false) {
816
				minute = parseInt(minute, 10);
817
			}
818
			if (second !== false) {
819
				second = parseInt(second, 10);
820
			}
821
			if (millisec !== false) {
822
				millisec = parseInt(millisec, 10);
823
			}
824
			if (microsec !== false) {
825
				microsec = parseInt(microsec, 10);
826
			}
827
			if (timezone !== false) {
828
				timezone = timezone.toString();
829
			}
830
831
			var ampm = o[hour < 12 ? 'amNames' : 'pmNames'][0];
832
833
			// If the update was done in the input field, the input field should not be updated.
834
			// If the update was done using the sliders, update the input field.
835
			var hasChanged = (
836
						hour !== parseInt(this.hour,10) || // sliders should all be numeric
837
						minute !== parseInt(this.minute,10) ||
838
						second !== parseInt(this.second,10) ||
839
						millisec !== parseInt(this.millisec,10) ||
840
						microsec !== parseInt(this.microsec,10) ||
841
						(this.ampm.length > 0 && (hour < 12) !== ($.inArray(this.ampm.toUpperCase(), this.amNames) !== -1)) ||
842
						(this.timezone !== null && timezone !== this.timezone.toString()) // could be numeric or "EST" format, so use toString()
843
					);
844
845
			if (hasChanged) {
846
847
				if (hour !== false) {
848
					this.hour = hour;
849
				}
850
				if (minute !== false) {
851
					this.minute = minute;
852
				}
853
				if (second !== false) {
854
					this.second = second;
855
				}
856
				if (millisec !== false) {
857
					this.millisec = millisec;
858
				}
859
				if (microsec !== false) {
860
					this.microsec = microsec;
861
				}
862
				if (timezone !== false) {
863
					this.timezone = timezone;
864
				}
865
866
				if (!this.inst) {
867
					this.inst = $.datepicker._getInst(this.$input[0]);
868
				}
869
870
				this._limitMinMaxDateTime(this.inst, true);
871
			}
872
			if (this.support.ampm) {
873
				this.ampm = ampm;
874
			}
875
876
			// Updates the time within the timepicker
877
			this.formattedTime = $.datepicker.formatTime(o.timeFormat, this, o);
878
			if (this.$timeObj) {
879
				if (pickerTimeFormat === o.timeFormat) {
880
					this.$timeObj.val(this.formattedTime + pickerTimeSuffix);
881
				}
882
				else {
883
					this.$timeObj.val($.datepicker.formatTime(pickerTimeFormat, this, o) + pickerTimeSuffix);
884
				}
885
				if (this.$timeObj[0].setSelectionRange) {
886
					var sPos = this.$timeObj[0].selectionStart;
887
					var ePos = this.$timeObj[0].selectionEnd;
888
					this.$timeObj[0].setSelectionRange(sPos, ePos);
889
				}
890
			}
891
892
			this.timeDefined = true;
893
			if (hasChanged) {
894
				this._updateDateTime();
895
				//this.$input.focus(); // may automatically open the picker on setDate
896
			}
897
		},
898
899
		/*
900
		* call custom onSelect.
901
		* bind to sliders slidestop, and grid click.
902
		*/
903
		_onSelectHandler: function () {
904
			var onSelect = this._defaults.onSelect || this.inst.settings.onSelect;
905
			var inputEl = this.$input ? this.$input[0] : null;
906
			if (onSelect && inputEl) {
907
				onSelect.apply(inputEl, [this.formattedDateTime, this]);
908
			}
909
		},
910
911
		/*
912
		* update our input with the new date time..
913
		*/
914
		_updateDateTime: function (dp_inst) {
915
			dp_inst = this.inst || dp_inst;
916
			var dtTmp = (dp_inst.currentYear > 0?
917
							new Date(dp_inst.currentYear, dp_inst.currentMonth, dp_inst.currentDay) :
918
							new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay)),
919
				dt = $.datepicker._daylightSavingAdjust(dtTmp),
920
				//dt = $.datepicker._daylightSavingAdjust(new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay)),
921
				//dt = $.datepicker._daylightSavingAdjust(new Date(dp_inst.currentYear, dp_inst.currentMonth, dp_inst.currentDay)),
922
				dateFmt = $.datepicker._get(dp_inst, 'dateFormat'),
923
				formatCfg = $.datepicker._getFormatConfig(dp_inst),
924
				timeAvailable = dt !== null && this.timeDefined;
925
			this.formattedDate = $.datepicker.formatDate(dateFmt, (dt === null ? new Date() : dt), formatCfg);
926
			var formattedDateTime = this.formattedDate;
927
928
			// if a slider was changed but datepicker doesn't have a value yet, set it
929
			if (dp_inst.lastVal === "") {
930
                dp_inst.currentYear = dp_inst.selectedYear;
931
                dp_inst.currentMonth = dp_inst.selectedMonth;
932
                dp_inst.currentDay = dp_inst.selectedDay;
933
            }
934
935
			/*
936
			* remove following lines to force every changes in date picker to change the input value
937
			* Bug descriptions: when an input field has a default value, and click on the field to pop up the date picker.
938
			* If the user manually empty the value in the input field, the date picker will never change selected value.
939
			*/
940
			//if (dp_inst.lastVal !== undefined && (dp_inst.lastVal.length > 0 && this.$input.val().length === 0)) {
941
			//	return;
942
			//}
943
944
			if (this._defaults.timeOnly === true && this._defaults.timeOnlyShowDate === false) {
945
				formattedDateTime = this.formattedTime;
946
			} else if ((this._defaults.timeOnly !== true && (this._defaults.alwaysSetTime || timeAvailable)) || (this._defaults.timeOnly === true && this._defaults.timeOnlyShowDate === true)) {
947
				formattedDateTime += this._defaults.separator + this.formattedTime + this._defaults.timeSuffix;
948
			}
949
950
			this.formattedDateTime = formattedDateTime;
951
952
			if (!this._defaults.showTimepicker) {
953
				this.$input.val(this.formattedDate);
954
			} else if (this.$altInput && this._defaults.timeOnly === false && this._defaults.altFieldTimeOnly === true) {
955
				this.$altInput.val(this.formattedTime);
956
				this.$input.val(this.formattedDate);
957
			} else if (this.$altInput) {
958
				this.$input.val(formattedDateTime);
959
				var altFormattedDateTime = '',
960
					altSeparator = this._defaults.altSeparator !== null ? this._defaults.altSeparator : this._defaults.separator,
961
					altTimeSuffix = this._defaults.altTimeSuffix !== null ? this._defaults.altTimeSuffix : this._defaults.timeSuffix;
962
963
				if (!this._defaults.timeOnly) {
964
					if (this._defaults.altFormat) {
965
						altFormattedDateTime = $.datepicker.formatDate(this._defaults.altFormat, (dt === null ? new Date() : dt), formatCfg);
966
					}
967
					else {
968
						altFormattedDateTime = this.formattedDate;
969
					}
970
971
					if (altFormattedDateTime) {
972
						altFormattedDateTime += altSeparator;
973
					}
974
				}
975
976
				if (this._defaults.altTimeFormat !== null) {
977
					altFormattedDateTime += $.datepicker.formatTime(this._defaults.altTimeFormat, this, this._defaults) + altTimeSuffix;
978
				}
979
				else {
980
					altFormattedDateTime += this.formattedTime + altTimeSuffix;
981
				}
982
				this.$altInput.val(altFormattedDateTime);
983
			} else {
984
				this.$input.val(formattedDateTime);
985
			}
986
987
			this.$input.trigger("change");
988
		},
989
990
		_onFocus: function () {
991
			if (!this.$input.val() && this._defaults.defaultValue) {
992
				this.$input.val(this._defaults.defaultValue);
993
				var inst = $.datepicker._getInst(this.$input.get(0)),
994
					tp_inst = $.datepicker._get(inst, 'timepicker');
995
				if (tp_inst) {
996
					if (tp_inst._defaults.timeOnly && (inst.input.val() !== inst.lastVal)) {
997
						try {
998
							$.datepicker._updateDatepicker(inst);
999
						} catch (err) {
1000
							$.timepicker.log(err);
1001
						}
1002
					}
1003
				}
1004
			}
1005
		},
1006
1007
		/*
1008
		* Small abstraction to control types
1009
		* We can add more, just be sure to follow the pattern: create, options, value
1010
		*/
1011
		_controls: {
1012
			// slider methods
1013
			slider: {
1014
				create: function (tp_inst, obj, unit, val, min, max, step) {
1015
					var rtl = tp_inst._defaults.isRTL; // if rtl go -60->0 instead of 0->60
1016
					return obj.prop('slide', null).slider({
1017
						orientation: "horizontal",
1018
						value: rtl ? val * -1 : val,
1019
						min: rtl ? max * -1 : min,
1020
						max: rtl ? min * -1 : max,
1021
						step: step,
1022
						slide: function (event, ui) {
1023
							tp_inst.control.value(tp_inst, $(this), unit, rtl ? ui.value * -1 : ui.value);
1024
							tp_inst._onTimeChange();
1025
						},
1026
						stop: function (event, ui) {
0 ignored issues
show
Unused Code introduced by
The parameter event is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter ui is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
1027
							tp_inst._onSelectHandler();
1028
						}
1029
					});
1030
				},
1031
				options: function (tp_inst, obj, unit, opts, val) {
1032
					if (tp_inst._defaults.isRTL) {
1033
						if (typeof(opts) === 'string') {
1034
							if (opts === 'min' || opts === 'max') {
1035
								if (val !== undefined) {
1036
									return obj.slider(opts, val * -1);
1037
								}
1038
								return Math.abs(obj.slider(opts));
1039
							}
1040
							return obj.slider(opts);
1041
						}
1042
						var min = opts.min,
1043
							max = opts.max;
1044
						opts.min = opts.max = null;
1045
						if (min !== undefined) {
1046
							opts.max = min * -1;
1047
						}
1048
						if (max !== undefined) {
1049
							opts.min = max * -1;
1050
						}
1051
						return obj.slider(opts);
1052
					}
1053
					if (typeof(opts) === 'string' && val !== undefined) {
1054
						return obj.slider(opts, val);
1055
					}
1056
					return obj.slider(opts);
1057
				},
1058
				value: function (tp_inst, obj, unit, val) {
1059
					if (tp_inst._defaults.isRTL) {
1060
						if (val !== undefined) {
1061
							return obj.slider('value', val * -1);
1062
						}
1063
						return Math.abs(obj.slider('value'));
1064
					}
1065
					if (val !== undefined) {
1066
						return obj.slider('value', val);
1067
					}
1068
					return obj.slider('value');
1069
				}
1070
			},
1071
			// select methods
1072
			select: {
1073
				create: function (tp_inst, obj, unit, val, min, max, step) {
1074
					var sel = '<select class="ui-timepicker-select ui-state-default ui-corner-all" data-unit="' + unit + '" data-min="' + min + '" data-max="' + max + '" data-step="' + step + '">',
1075
						format = tp_inst._defaults.pickerTimeFormat || tp_inst._defaults.timeFormat;
1076
1077
					for (var i = min; i <= max; i += step) {
1078
						sel += '<option value="' + i + '"' + (i === val ? ' selected' : '') + '>';
1079
						if (unit === 'hour') {
1080
							sel += $.datepicker.formatTime($.trim(format.replace(/[^ht ]/ig, '')), {hour: i}, tp_inst._defaults);
1081
						}
1082
						else if (unit === 'millisec' || unit === 'microsec' || i >= 10) { sel += i; }
1083
						else {sel += '0' + i.toString(); }
1084
						sel += '</option>';
1085
					}
1086
					sel += '</select>';
1087
1088
					obj.children('select').remove();
1089
1090
					$(sel).appendTo(obj).change(function (e) {
0 ignored issues
show
Unused Code introduced by
The parameter e is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
1091
						tp_inst._onTimeChange();
1092
						tp_inst._onSelectHandler();
1093
						tp_inst._afterInject();
1094
					});
1095
1096
					return obj;
1097
				},
1098
				options: function (tp_inst, obj, unit, opts, val) {
1099
					var o = {},
1100
						$t = obj.children('select');
1101
					if (typeof(opts) === 'string') {
1102
						if (val === undefined) {
1103
							return $t.data(opts);
1104
						}
1105
						o[opts] = val;
1106
					}
1107
					else { o = opts; }
1108
					return tp_inst.control.create(tp_inst, obj, $t.data('unit'), $t.val(), o.min>=0 ? o.min : $t.data('min'), o.max || $t.data('max'), o.step || $t.data('step'));
1109
				},
1110
				value: function (tp_inst, obj, unit, val) {
1111
					var $t = obj.children('select');
1112
					if (val !== undefined) {
1113
						return $t.val(val);
1114
					}
1115
					return $t.val();
1116
				}
1117
			}
1118
		} // end _controls
1119
1120
	});
1121
1122
	$.fn.extend({
1123
		/*
1124
		* shorthand just to use timepicker.
1125
		*/
1126
		timepicker: function (o) {
1127
			o = o || {};
1128
			var tmp_args = Array.prototype.slice.call(arguments);
1129
1130
			if (typeof o === 'object') {
1131
				tmp_args[0] = $.extend(o, {
1132
					timeOnly: true
1133
				});
1134
			}
1135
1136
			return $(this).each(function () {
1137
				$.fn.datetimepicker.apply($(this), tmp_args);
1138
			});
1139
		},
1140
1141
		/*
1142
		* extend timepicker to datepicker
1143
		*/
1144
		datetimepicker: function (o) {
1145
			o = o || {};
1146
			var tmp_args = arguments;
1147
1148
			if (typeof(o) === 'string') {
1149
				if (o === 'getDate'  || (o === 'option' && tmp_args.length === 2 && typeof (tmp_args[1]) === 'string')) {
1150
					return $.fn.datepicker.apply($(this[0]), tmp_args);
1151
				} else {
1152
					return this.each(function () {
1153
						var $t = $(this);
1154
						$t.datepicker.apply($t, tmp_args);
1155
					});
1156
				}
1157
			} else {
1158
				return this.each(function () {
1159
					var $t = $(this);
1160
					$t.datepicker($.timepicker._newInst($t, o)._defaults);
1161
				});
1162
			}
1163
		}
1164
	});
1165
1166
	/*
1167
	* Public Utility to parse date and time
1168
	*/
1169
	$.datepicker.parseDateTime = function (dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings) {
1170
		var parseRes = parseDateTimeInternal(dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings);
1171
		if (parseRes.timeObj) {
1172
			var t = parseRes.timeObj;
1173
			parseRes.date.setHours(t.hour, t.minute, t.second, t.millisec);
1174
			parseRes.date.setMicroseconds(t.microsec);
1175
		}
1176
1177
		return parseRes.date;
1178
	};
1179
1180
	/*
1181
	* Public utility to parse time
1182
	*/
1183
	$.datepicker.parseTime = function (timeFormat, timeString, options) {
1184
		var o = extendRemove(extendRemove({}, $.timepicker._defaults), options || {}),
1185
			iso8601 = (timeFormat.replace(/\'.*?\'/g, '').indexOf('Z') !== -1);
0 ignored issues
show
Unused Code introduced by
The variable iso8601 seems to be never used. Consider removing it.
Loading history...
1186
1187
		// Strict parse requires the timeString to match the timeFormat exactly
1188
		var strictParse = function (f, s, o) {
1189
1190
			// pattern for standard and localized AM/PM markers
1191
			var getPatternAmpm = function (amNames, pmNames) {
1192
				var markers = [];
1193
				if (amNames) {
1194
					$.merge(markers, amNames);
1195
				}
1196
				if (pmNames) {
1197
					$.merge(markers, pmNames);
1198
				}
1199
				markers = $.map(markers, function (val) {
1200
					return val.replace(/[.*+?|()\[\]{}\\]/g, '\\$&');
1201
				});
1202
				return '(' + markers.join('|') + ')?';
1203
			};
1204
1205
			// figure out position of time elements.. cause js cant do named captures
1206
			var getFormatPositions = function (timeFormat) {
1207
				var finds = timeFormat.toLowerCase().match(/(h{1,2}|m{1,2}|s{1,2}|l{1}|c{1}|t{1,2}|z|'.*?')/g),
1208
					orders = {
1209
						h: -1,
1210
						m: -1,
1211
						s: -1,
1212
						l: -1,
1213
						c: -1,
1214
						t: -1,
1215
						z: -1
1216
					};
1217
1218
				if (finds) {
1219
					for (var i = 0; i < finds.length; i++) {
1220
						if (orders[finds[i].toString().charAt(0)] === -1) {
1221
							orders[finds[i].toString().charAt(0)] = i + 1;
1222
						}
1223
					}
1224
				}
1225
				return orders;
1226
			};
1227
1228
			var regstr = '^' + f.toString()
1229
					.replace(/([hH]{1,2}|mm?|ss?|[tT]{1,2}|[zZ]|[lc]|'.*?')/g, function (match) {
1230
							var ml = match.length;
1231
							switch (match.charAt(0).toLowerCase()) {
1232
							case 'h':
1233
								return ml === 1 ? '(\\d?\\d)' : '(\\d{' + ml + '})';
1234
							case 'm':
1235
								return ml === 1 ? '(\\d?\\d)' : '(\\d{' + ml + '})';
1236
							case 's':
1237
								return ml === 1 ? '(\\d?\\d)' : '(\\d{' + ml + '})';
1238
							case 'l':
1239
								return '(\\d?\\d?\\d)';
1240
							case 'c':
1241
								return '(\\d?\\d?\\d)';
1242
							case 'z':
1243
								return '(z|[-+]\\d\\d:?\\d\\d|\\S+)?';
1244
							case 't':
1245
								return getPatternAmpm(o.amNames, o.pmNames);
1246
							default:    // literal escaped in quotes
1247
								return '(' + match.replace(/\'/g, "").replace(/(\.|\$|\^|\\|\/|\(|\)|\[|\]|\?|\+|\*)/g, function (m) { return "\\" + m; }) + ')?';
1248
							}
1249
						})
1250
					.replace(/\s/g, '\\s?') +
1251
					o.timeSuffix + '$',
1252
				order = getFormatPositions(f),
1253
				ampm = '',
1254
				treg;
1255
1256
			treg = s.match(new RegExp(regstr, 'i'));
1257
1258
			var resTime = {
1259
				hour: 0,
1260
				minute: 0,
1261
				second: 0,
1262
				millisec: 0,
1263
				microsec: 0
1264
			};
1265
1266
			if (treg) {
1267
				if (order.t !== -1) {
1268
					if (treg[order.t] === undefined || treg[order.t].length === 0) {
1269
						ampm = '';
1270
						resTime.ampm = '';
1271
					} else {
1272
						ampm = $.inArray(treg[order.t].toUpperCase(), $.map(o.amNames, function (x,i) { return x.toUpperCase(); })) !== -1 ? 'AM' : 'PM';
0 ignored issues
show
Unused Code introduced by
The parameter i is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
1273
						resTime.ampm = o[ampm === 'AM' ? 'amNames' : 'pmNames'][0];
1274
					}
1275
				}
1276
1277
				if (order.h !== -1) {
1278
					if (ampm === 'AM' && treg[order.h] === '12') {
1279
						resTime.hour = 0; // 12am = 0 hour
1280
					} else {
1281
						if (ampm === 'PM' && treg[order.h] !== '12') {
1282
							resTime.hour = parseInt(treg[order.h], 10) + 12; // 12pm = 12 hour, any other pm = hour + 12
1283
						} else {
1284
							resTime.hour = Number(treg[order.h]);
1285
						}
1286
					}
1287
				}
1288
1289
				if (order.m !== -1) {
1290
					resTime.minute = Number(treg[order.m]);
1291
				}
1292
				if (order.s !== -1) {
1293
					resTime.second = Number(treg[order.s]);
1294
				}
1295
				if (order.l !== -1) {
1296
					resTime.millisec = Number(treg[order.l]);
1297
				}
1298
				if (order.c !== -1) {
1299
					resTime.microsec = Number(treg[order.c]);
1300
				}
1301
				if (order.z !== -1 && treg[order.z] !== undefined) {
1302
					resTime.timezone = $.timepicker.timezoneOffsetNumber(treg[order.z]);
1303
				}
1304
1305
1306
				return resTime;
1307
			}
1308
			return false;
1309
		};// end strictParse
1310
1311
		// First try JS Date, if that fails, use strictParse
1312
		var looseParse = function (f, s, o) {
1313
			try {
1314
				var d = new Date('2012-01-01 ' + s);
1315
				if (isNaN(d.getTime())) {
1316
					d = new Date('2012-01-01T' + s);
1317
					if (isNaN(d.getTime())) {
1318
						d = new Date('01/01/2012 ' + s);
1319
						if (isNaN(d.getTime())) {
1320
							throw "Unable to parse time with native Date: " + s;
1321
						}
1322
					}
1323
				}
1324
1325
				return {
1326
					hour: d.getHours(),
1327
					minute: d.getMinutes(),
1328
					second: d.getSeconds(),
1329
					millisec: d.getMilliseconds(),
1330
					microsec: d.getMicroseconds(),
1331
					timezone: d.getTimezoneOffset() * -1
1332
				};
1333
			}
1334
			catch (err) {
1335
				try {
1336
					return strictParse(f, s, o);
1337
				}
1338
				catch (err2) {
1339
					$.timepicker.log("Unable to parse \ntimeString: " + s + "\ntimeFormat: " + f);
1340
				}
1341
			}
1342
			return false;
1343
		}; // end looseParse
1344
1345
		if (typeof o.parse === "function") {
1346
			return o.parse(timeFormat, timeString, o);
1347
		}
1348
		if (o.parse === 'loose') {
1349
			return looseParse(timeFormat, timeString, o);
1350
		}
1351
		return strictParse(timeFormat, timeString, o);
1352
	};
1353
1354
	/**
1355
	 * Public utility to format the time
1356
	 * @param {string} format format of the time
1357
	 * @param {Object} time Object not a Date for timezones
1358
	 * @param {Object} [options] essentially the regional[].. amNames, pmNames, ampm
1359
	 * @returns {string} the formatted time
1360
	 */
1361
	$.datepicker.formatTime = function (format, time, options) {
1362
		options = options || {};
1363
		options = $.extend({}, $.timepicker._defaults, options);
1364
		time = $.extend({
1365
			hour: 0,
1366
			minute: 0,
1367
			second: 0,
1368
			millisec: 0,
1369
			microsec: 0,
1370
			timezone: null
1371
		}, time);
1372
1373
		var tmptime = format,
1374
			ampmName = options.amNames[0],
1375
			hour = parseInt(time.hour, 10);
1376
1377
		if (hour > 11) {
1378
			ampmName = options.pmNames[0];
1379
		}
1380
1381
		tmptime = tmptime.replace(/(?:HH?|hh?|mm?|ss?|[tT]{1,2}|[zZ]|[lc]|'.*?')/g, function (match) {
1382
			switch (match) {
1383
			case 'HH':
1384
				return ('0' + hour).slice(-2);
1385
			case 'H':
1386
				return hour;
1387
			case 'hh':
1388
				return ('0' + convert24to12(hour)).slice(-2);
1389
			case 'h':
1390
				return convert24to12(hour);
1391
			case 'mm':
1392
				return ('0' + time.minute).slice(-2);
1393
			case 'm':
1394
				return time.minute;
1395
			case 'ss':
1396
				return ('0' + time.second).slice(-2);
1397
			case 's':
1398
				return time.second;
1399
			case 'l':
1400
				return ('00' + time.millisec).slice(-3);
1401
			case 'c':
1402
				return ('00' + time.microsec).slice(-3);
1403
			case 'z':
1404
				return $.timepicker.timezoneOffsetString(time.timezone === null ? options.timezone : time.timezone, false);
1405
			case 'Z':
1406
				return $.timepicker.timezoneOffsetString(time.timezone === null ? options.timezone : time.timezone, true);
1407
			case 'T':
1408
				return ampmName.charAt(0).toUpperCase();
1409
			case 'TT':
1410
				return ampmName.toUpperCase();
1411
			case 't':
1412
				return ampmName.charAt(0).toLowerCase();
1413
			case 'tt':
1414
				return ampmName.toLowerCase();
1415
			default:
1416
				return match.replace(/'/g, "");
1417
			}
1418
		});
1419
1420
		return tmptime;
1421
	};
1422
1423
	/*
1424
	* the bad hack :/ override datepicker so it doesn't close on select
1425
	// inspired: http://stackoverflow.com/questions/1252512/jquery-datepicker-prevent-closing-picker-when-clicking-a-date/1762378#1762378
1426
	*/
1427
	$.datepicker._base_selectDate = $.datepicker._selectDate;
1428
	$.datepicker._selectDate = function (id, dateStr) {
1429
		var inst = this._getInst($(id)[0]),
1430
			tp_inst = this._get(inst, 'timepicker'),
1431
			was_inline;
1432
1433
		if (tp_inst && inst.settings.showTimepicker) {
1434
			tp_inst._limitMinMaxDateTime(inst, true);
1435
			was_inline = inst.inline;
1436
			inst.inline = inst.stay_open = true;
1437
			//This way the onSelect handler called from calendarpicker get the full dateTime
1438
			this._base_selectDate(id, dateStr);
1439
			inst.inline = was_inline;
1440
			inst.stay_open = false;
1441
			this._notifyChange(inst);
1442
			this._updateDatepicker(inst);
1443
		} else {
1444
			this._base_selectDate(id, dateStr);
1445
		}
1446
	};
1447
1448
	/*
1449
	* second bad hack :/ override datepicker so it triggers an event when changing the input field
1450
	* and does not redraw the datepicker on every selectDate event
1451
	*/
1452
	$.datepicker._base_updateDatepicker = $.datepicker._updateDatepicker;
1453
	$.datepicker._updateDatepicker = function (inst) {
1454
1455
		// don't popup the datepicker if there is another instance already opened
1456
		var input = inst.input[0];
1457
		if ($.datepicker._curInst && $.datepicker._curInst !== inst && $.datepicker._datepickerShowing && $.datepicker._lastInput !== input) {
1458
			return;
1459
		}
1460
1461
		if (typeof(inst.stay_open) !== 'boolean' || inst.stay_open === false) {
1462
1463
			this._base_updateDatepicker(inst);
1464
1465
			// Reload the time control when changing something in the input text field.
1466
			var tp_inst = this._get(inst, 'timepicker');
1467
			if (tp_inst) {
1468
				tp_inst._addTimePicker(inst);
1469
			}
1470
		}
1471
	};
1472
1473
	/*
1474
	* third bad hack :/ override datepicker so it allows spaces and colon in the input field
1475
	*/
1476
	$.datepicker._base_doKeyPress = $.datepicker._doKeyPress;
1477
	$.datepicker._doKeyPress = function (event) {
1478
		var inst = $.datepicker._getInst(event.target),
1479
			tp_inst = $.datepicker._get(inst, 'timepicker');
1480
1481
		if (tp_inst) {
1482
			if ($.datepicker._get(inst, 'constrainInput')) {
1483
				var ampm = tp_inst.support.ampm,
1484
					tz = tp_inst._defaults.showTimezone !== null ? tp_inst._defaults.showTimezone : tp_inst.support.timezone,
1485
					dateChars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat')),
1486
					datetimeChars = tp_inst._defaults.timeFormat.toString()
1487
											.replace(/[hms]/g, '')
1488
											.replace(/TT/g, ampm ? 'APM' : '')
1489
											.replace(/Tt/g, ampm ? 'AaPpMm' : '')
1490
											.replace(/tT/g, ampm ? 'AaPpMm' : '')
1491
											.replace(/T/g, ampm ? 'AP' : '')
1492
											.replace(/tt/g, ampm ? 'apm' : '')
1493
											.replace(/t/g, ampm ? 'ap' : '') +
1494
											" " + tp_inst._defaults.separator +
1495
											tp_inst._defaults.timeSuffix +
1496
											(tz ? tp_inst._defaults.timezoneList.join('') : '') +
1497
											(tp_inst._defaults.amNames.join('')) + (tp_inst._defaults.pmNames.join('')) +
1498
											dateChars,
1499
					chr = String.fromCharCode(event.charCode === undefined ? event.keyCode : event.charCode);
1500
				return event.ctrlKey || (chr < ' ' || !dateChars || datetimeChars.indexOf(chr) > -1);
1501
			}
1502
		}
1503
1504
		return $.datepicker._base_doKeyPress(event);
1505
	};
1506
1507
	/*
1508
	* Fourth bad hack :/ override _updateAlternate function used in inline mode to init altField
1509
	* Update any alternate field to synchronise with the main field.
1510
	*/
1511
	$.datepicker._base_updateAlternate = $.datepicker._updateAlternate;
1512
	$.datepicker._updateAlternate = function (inst) {
1513
		var tp_inst = this._get(inst, 'timepicker');
1514
		if (tp_inst) {
1515
			var altField = tp_inst._defaults.altField;
1516
			if (altField) { // update alternate field too
1517
				var altFormat = tp_inst._defaults.altFormat || tp_inst._defaults.dateFormat,
1518
					date = this._getDate(inst),
1519
					formatCfg = $.datepicker._getFormatConfig(inst),
1520
					altFormattedDateTime = '',
1521
					altSeparator = tp_inst._defaults.altSeparator ? tp_inst._defaults.altSeparator : tp_inst._defaults.separator,
1522
					altTimeSuffix = tp_inst._defaults.altTimeSuffix ? tp_inst._defaults.altTimeSuffix : tp_inst._defaults.timeSuffix,
1523
					altTimeFormat = tp_inst._defaults.altTimeFormat !== null ? tp_inst._defaults.altTimeFormat : tp_inst._defaults.timeFormat;
1524
1525
				altFormattedDateTime += $.datepicker.formatTime(altTimeFormat, tp_inst, tp_inst._defaults) + altTimeSuffix;
1526
				if (!tp_inst._defaults.timeOnly && !tp_inst._defaults.altFieldTimeOnly && date !== null) {
1527
					if (tp_inst._defaults.altFormat) {
1528
						altFormattedDateTime = $.datepicker.formatDate(tp_inst._defaults.altFormat, date, formatCfg) + altSeparator + altFormattedDateTime;
1529
					}
1530
					else {
1531
						altFormattedDateTime = tp_inst.formattedDate + altSeparator + altFormattedDateTime;
1532
					}
1533
				}
1534
				$(altField).val( inst.input.val() ? altFormattedDateTime : "");
1535
			}
1536
		}
1537
		else {
1538
			$.datepicker._base_updateAlternate(inst);
1539
		}
1540
	};
1541
1542
	/*
1543
	* Override key up event to sync manual input changes.
1544
	*/
1545
	$.datepicker._base_doKeyUp = $.datepicker._doKeyUp;
1546
	$.datepicker._doKeyUp = function (event) {
1547
		var inst = $.datepicker._getInst(event.target),
1548
			tp_inst = $.datepicker._get(inst, 'timepicker');
1549
1550
		if (tp_inst) {
1551
			if (tp_inst._defaults.timeOnly && (inst.input.val() !== inst.lastVal)) {
1552
				try {
1553
					$.datepicker._updateDatepicker(inst);
1554
				} catch (err) {
1555
					$.timepicker.log(err);
1556
				}
1557
			}
1558
		}
1559
1560
		return $.datepicker._base_doKeyUp(event);
1561
	};
1562
1563
	/*
1564
	* override "Today" button to also grab the time and set it to input field.
1565
	*/
1566
	$.datepicker._base_gotoToday = $.datepicker._gotoToday;
1567
	$.datepicker._gotoToday = function (id) {
1568
		var inst = this._getInst($(id)[0]);
1569
		this._base_gotoToday(id);
1570
		var tp_inst = this._get(inst, 'timepicker');
1571
		if (!tp_inst) {
1572
		  return;
1573
		}
1574
1575
		var tzoffset = $.timepicker.timezoneOffsetNumber(tp_inst.timezone);
1576
		var now = new Date();
1577
		now.setMinutes(now.getMinutes() + now.getTimezoneOffset() + parseInt(tzoffset, 10));
1578
		this._setTime(inst, now);
1579
		this._setDate(inst, now);
1580
		tp_inst._onSelectHandler();
1581
	};
1582
1583
	/*
1584
	* Disable & enable the Time in the datetimepicker
1585
	*/
1586
	$.datepicker._disableTimepickerDatepicker = function (target) {
1587
		var inst = this._getInst(target);
1588
		if (!inst) {
1589
			return;
1590
		}
1591
1592
		var tp_inst = this._get(inst, 'timepicker');
1593
		$(target).datepicker('getDate'); // Init selected[Year|Month|Day]
1594
		if (tp_inst) {
1595
			inst.settings.showTimepicker = false;
1596
			tp_inst._defaults.showTimepicker = false;
1597
			tp_inst._updateDateTime(inst);
1598
		}
1599
	};
1600
1601
	$.datepicker._enableTimepickerDatepicker = function (target) {
1602
		var inst = this._getInst(target);
1603
		if (!inst) {
1604
			return;
1605
		}
1606
1607
		var tp_inst = this._get(inst, 'timepicker');
1608
		$(target).datepicker('getDate'); // Init selected[Year|Month|Day]
1609
		if (tp_inst) {
1610
			inst.settings.showTimepicker = true;
1611
			tp_inst._defaults.showTimepicker = true;
1612
			tp_inst._addTimePicker(inst); // Could be disabled on page load
1613
			tp_inst._updateDateTime(inst);
1614
		}
1615
	};
1616
1617
	/*
1618
	* Create our own set time function
1619
	*/
1620
	$.datepicker._setTime = function (inst, date) {
1621
		var tp_inst = this._get(inst, 'timepicker');
1622
		if (tp_inst) {
1623
			var defaults = tp_inst._defaults;
1624
1625
			// calling _setTime with no date sets time to defaults
1626
			tp_inst.hour = date ? date.getHours() : defaults.hour;
1627
			tp_inst.minute = date ? date.getMinutes() : defaults.minute;
1628
			tp_inst.second = date ? date.getSeconds() : defaults.second;
1629
			tp_inst.millisec = date ? date.getMilliseconds() : defaults.millisec;
1630
			tp_inst.microsec = date ? date.getMicroseconds() : defaults.microsec;
1631
1632
			//check if within min/max times..
1633
			tp_inst._limitMinMaxDateTime(inst, true);
1634
1635
			tp_inst._onTimeChange();
1636
			tp_inst._updateDateTime(inst);
1637
		}
1638
	};
1639
1640
	/*
1641
	* Create new public method to set only time, callable as $().datepicker('setTime', date)
1642
	*/
1643
	$.datepicker._setTimeDatepicker = function (target, date, withDate) {
1644
		var inst = this._getInst(target);
1645
		if (!inst) {
1646
			return;
1647
		}
1648
1649
		var tp_inst = this._get(inst, 'timepicker');
1650
1651
		if (tp_inst) {
1652
			this._setDateFromField(inst);
1653
			var tp_date;
1654
			if (date) {
1655
				if (typeof date === "string") {
1656
					tp_inst._parseTime(date, withDate);
1657
					tp_date = new Date();
1658
					tp_date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec);
1659
					tp_date.setMicroseconds(tp_inst.microsec);
1660
				} else {
1661
					tp_date = new Date(date.getTime());
1662
					tp_date.setMicroseconds(date.getMicroseconds());
1663
				}
1664
				if (tp_date.toString() === 'Invalid Date') {
1665
					tp_date = undefined;
1666
				}
1667
				this._setTime(inst, tp_date);
1668
			}
1669
		}
1670
1671
	};
1672
1673
	/*
1674
	* override setDate() to allow setting time too within Date object
1675
	*/
1676
	$.datepicker._base_setDateDatepicker = $.datepicker._setDateDatepicker;
1677
	$.datepicker._setDateDatepicker = function (target, _date) {
1678
		var inst = this._getInst(target);
1679
		var date = _date;
1680
		if (!inst) {
1681
			return;
1682
		}
1683
1684
		if (typeof(_date) === 'string') {
1685
			date = new Date(_date);
1686
			if (!date.getTime()) {
1687
				this._base_setDateDatepicker.apply(this, arguments);
1688
				date = $(target).datepicker('getDate');
1689
			}
1690
		}
1691
1692
		var tp_inst = this._get(inst, 'timepicker');
1693
		var tp_date;
1694
		if (date instanceof Date) {
1695
			tp_date = new Date(date.getTime());
1696
			tp_date.setMicroseconds(date.getMicroseconds());
1697
		} else {
1698
			tp_date = date;
1699
		}
1700
1701
		// This is important if you are using the timezone option, javascript's Date
1702
		// object will only return the timezone offset for the current locale, so we
1703
		// adjust it accordingly.  If not using timezone option this won't matter..
1704
		// If a timezone is different in tp, keep the timezone as is
1705
		if (tp_inst && tp_date) {
1706
			// look out for DST if tz wasn't specified
1707
			if (!tp_inst.support.timezone && tp_inst._defaults.timezone === null) {
1708
				tp_inst.timezone = tp_date.getTimezoneOffset() * -1;
1709
			}
1710
			date = $.timepicker.timezoneAdjust(date, $.timepicker.timezoneOffsetString(-date.getTimezoneOffset()), tp_inst.timezone);
0 ignored issues
show
Unused Code introduced by
The assignment to variable date seems to be never used. Consider removing it.
Loading history...
1711
			tp_date = $.timepicker.timezoneAdjust(tp_date, $.timepicker.timezoneOffsetString(-tp_date.getTimezoneOffset()), tp_inst.timezone);
1712
		}
1713
1714
		this._updateDatepicker(inst);
1715
		this._base_setDateDatepicker.apply(this, arguments);
1716
		this._setTimeDatepicker(target, tp_date, true);
1717
	};
1718
1719
	/*
1720
	* override getDate() to allow getting time too within Date object
1721
	*/
1722
	$.datepicker._base_getDateDatepicker = $.datepicker._getDateDatepicker;
1723
	$.datepicker._getDateDatepicker = function (target, noDefault) {
1724
		var inst = this._getInst(target);
1725
		if (!inst) {
1726
			return;
1727
		}
1728
1729
		var tp_inst = this._get(inst, 'timepicker');
1730
1731
		if (tp_inst) {
1732
			// if it hasn't yet been defined, grab from field
1733
			if (inst.lastVal === undefined) {
1734
				this._setDateFromField(inst, noDefault);
1735
			}
1736
1737
			var date = this._getDate(inst);
1738
1739
			var currDT = null;
0 ignored issues
show
Unused Code introduced by
The assignment to currDT seems to be never used. If you intend to free memory here, this is not necessary since the variable leaves the scope anyway.
Loading history...
1740
1741
			if (tp_inst.$altInput && tp_inst._defaults.altFieldTimeOnly) {
1742
				currDT = tp_inst.$input.val() + ' ' + tp_inst.$altInput.val();
1743
			}
1744
			else if (tp_inst.$input.get(0).tagName !== 'INPUT' && tp_inst.$altInput) {
1745
				/**
1746
				 * in case the datetimepicker has been applied to a non-input tag for inline UI,
1747
				 * and the user has not configured the plugin to display only time in altInput,
1748
				 * pick current date time from the altInput (and hope for the best, for now, until "ER1" is applied)
1749
				 *
1750
				 * @todo ER1. Since altInput can have a totally difference format, convert it to standard format by reading input format from "altFormat" and "altTimeFormat" option values
1751
				 */
1752
				currDT = tp_inst.$altInput.val();
1753
			}
1754
			else {
1755
				currDT = tp_inst.$input.val();
1756
			}
1757
1758
			if (date && tp_inst._parseTime(currDT, !inst.settings.timeOnly)) {
1759
				date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec);
1760
				date.setMicroseconds(tp_inst.microsec);
1761
1762
				// This is important if you are using the timezone option, javascript's Date
1763
				// object will only return the timezone offset for the current locale, so we
1764
				// adjust it accordingly.  If not using timezone option this won't matter..
1765
				if (tp_inst.timezone != null) {
1766
					// look out for DST if tz wasn't specified
1767
					if (!tp_inst.support.timezone && tp_inst._defaults.timezone === null) {
1768
						tp_inst.timezone = date.getTimezoneOffset() * -1;
1769
					}
1770
					date = $.timepicker.timezoneAdjust(date, tp_inst.timezone, $.timepicker.timezoneOffsetString(-date.getTimezoneOffset()));
1771
				}
1772
			}
1773
			return date;
1774
		}
1775
		return this._base_getDateDatepicker(target, noDefault);
1776
	};
1777
1778
	/*
1779
	* override parseDate() because UI 1.8.14 throws an error about "Extra characters"
1780
	* An option in datapicker to ignore extra format characters would be nicer.
1781
	*/
1782
	$.datepicker._base_parseDate = $.datepicker.parseDate;
1783
	$.datepicker.parseDate = function (format, value, settings) {
1784
		var date;
1785
		try {
1786
			date = this._base_parseDate(format, value, settings);
1787
		} catch (err) {
1788
			// Hack!  The error message ends with a colon, a space, and
1789
			// the "extra" characters.  We rely on that instead of
1790
			// attempting to perfectly reproduce the parsing algorithm.
1791
			if (err.indexOf(":") >= 0) {
1792
				date = this._base_parseDate(format, value.substring(0, value.length - (err.length - err.indexOf(':') - 2)), settings);
1793
				$.timepicker.log("Error parsing the date string: " + err + "\ndate string = " + value + "\ndate format = " + format);
1794
			} else {
1795
				throw err;
1796
			}
1797
		}
1798
		return date;
1799
	};
1800
1801
	/*
1802
	* override formatDate to set date with time to the input
1803
	*/
1804
	$.datepicker._base_formatDate = $.datepicker._formatDate;
1805
	$.datepicker._formatDate = function (inst, day, month, year) {
0 ignored issues
show
Unused Code introduced by
The parameter day is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter year is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter month is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
1806
		var tp_inst = this._get(inst, 'timepicker');
1807
		if (tp_inst) {
1808
			tp_inst._updateDateTime(inst);
1809
			return tp_inst.$input.val();
1810
		}
1811
		return this._base_formatDate(inst);
1812
	};
1813
1814
	/*
1815
	* override options setter to add time to maxDate(Time) and minDate(Time). MaxDate
1816
	*/
1817
	$.datepicker._base_optionDatepicker = $.datepicker._optionDatepicker;
1818
	$.datepicker._optionDatepicker = function (target, name, value) {
1819
		var inst = this._getInst(target),
1820
			name_clone;
1821
		if (!inst) {
1822
			return null;
1823
		}
1824
1825
		var tp_inst = this._get(inst, 'timepicker');
1826
		if (tp_inst) {
1827
			var min = null,
1828
				max = null,
1829
				onselect = null,
1830
				overrides = tp_inst._defaults.evnts,
1831
				fns = {},
1832
				prop,
1833
				ret,
1834
				oldVal,
1835
				$target;
1836
			if (typeof name === 'string') { // if min/max was set with the string
1837
				if (name === 'minDate' || name === 'minDateTime') {
1838
					min = value;
1839
				} else if (name === 'maxDate' || name === 'maxDateTime') {
1840
					max = value;
1841
				} else if (name === 'onSelect') {
1842
					onselect = value;
1843
				} else if (overrides.hasOwnProperty(name)) {
1844
					if (typeof (value) === 'undefined') {
1845
						return overrides[name];
1846
					}
1847
					fns[name] = value;
1848
					name_clone = {}; //empty results in exiting function after overrides updated
1849
				}
1850
			} else if (typeof name === 'object') { //if min/max was set with the JSON
1851
				if (name.minDate) {
1852
					min = name.minDate;
1853
				} else if (name.minDateTime) {
1854
					min = name.minDateTime;
1855
				} else if (name.maxDate) {
1856
					max = name.maxDate;
1857
				} else if (name.maxDateTime) {
1858
					max = name.maxDateTime;
1859
				}
1860
				for (prop in overrides) {
1861
					if (overrides.hasOwnProperty(prop) && name[prop]) {
1862
						fns[prop] = name[prop];
1863
					}
1864
				}
1865
			}
1866
			for (prop in fns) {
1867
				if (fns.hasOwnProperty(prop)) {
1868
					overrides[prop] = fns[prop];
1869
					if (!name_clone) { name_clone = $.extend({}, name); }
1870
					delete name_clone[prop];
1871
				}
1872
			}
1873
			if (name_clone && isEmptyObject(name_clone)) { return; }
1874
			if (min) { //if min was set
1875
				if (min === 0) {
1876
					min = new Date();
1877
				} else {
1878
					min = new Date(min);
1879
				}
1880
				tp_inst._defaults.minDate = min;
1881
				tp_inst._defaults.minDateTime = min;
1882
			} else if (max) { //if max was set
1883
				if (max === 0) {
1884
					max = new Date();
1885
				} else {
1886
					max = new Date(max);
1887
				}
1888
				tp_inst._defaults.maxDate = max;
1889
				tp_inst._defaults.maxDateTime = max;
1890
			} else if (onselect) {
1891
				tp_inst._defaults.onSelect = onselect;
1892
			}
1893
1894
			// Datepicker will override our date when we call _base_optionDatepicker when
1895
			// calling minDate/maxDate, so we will first grab the value, call
1896
			// _base_optionDatepicker, then set our value back.
1897
			if(min || max){
1898
				$target = $(target);
1899
				oldVal = $target.datetimepicker('getDate');
1900
				ret = this._base_optionDatepicker.call($.datepicker, target, name_clone || name, value);
1901
				$target.datetimepicker('setDate', oldVal);
1902
				return ret;
1903
			}
1904
		}
1905
		if (value === undefined) {
1906
			return this._base_optionDatepicker.call($.datepicker, target, name);
1907
		}
1908
		return this._base_optionDatepicker.call($.datepicker, target, name_clone || name, value);
1909
	};
1910
1911
	/*
1912
	* jQuery isEmptyObject does not check hasOwnProperty - if someone has added to the object prototype,
1913
	* it will return false for all objects
1914
	*/
1915
	var isEmptyObject = function (obj) {
1916
		var prop;
1917
		for (prop in obj) {
1918
			if (obj.hasOwnProperty(prop)) {
1919
				return false;
1920
			}
1921
		}
1922
		return true;
1923
	};
1924
1925
	/*
1926
	* jQuery extend now ignores nulls!
1927
	*/
1928
	var extendRemove = function (target, props) {
1929
		$.extend(target, props);
1930
		for (var name in props) {
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
1931
			if (props[name] === null || props[name] === undefined) {
1932
				target[name] = props[name];
1933
			}
1934
		}
1935
		return target;
1936
	};
1937
1938
	/*
1939
	* Determine by the time format which units are supported
1940
	* Returns an object of booleans for each unit
1941
	*/
1942
	var detectSupport = function (timeFormat) {
1943
		var tf = timeFormat.replace(/'.*?'/g, '').toLowerCase(), // removes literals
1944
			isIn = function (f, t) { // does the format contain the token?
1945
					return f.indexOf(t) !== -1 ? true : false;
1946
				};
1947
		return {
1948
				hour: isIn(tf, 'h'),
1949
				minute: isIn(tf, 'm'),
1950
				second: isIn(tf, 's'),
1951
				millisec: isIn(tf, 'l'),
1952
				microsec: isIn(tf, 'c'),
1953
				timezone: isIn(tf, 'z'),
1954
				ampm: isIn(tf, 't') && isIn(timeFormat, 'h'),
1955
				iso8601: isIn(timeFormat, 'Z')
1956
			};
1957
	};
1958
1959
	/*
1960
	* Converts 24 hour format into 12 hour
1961
	* Returns 12 hour without leading 0
1962
	*/
1963
	var convert24to12 = function (hour) {
1964
		hour %= 12;
1965
1966
		if (hour === 0) {
1967
			hour = 12;
1968
		}
1969
1970
		return String(hour);
1971
	};
1972
1973
	var computeEffectiveSetting = function (settings, property) {
1974
		return settings && settings[property] ? settings[property] : $.timepicker._defaults[property];
1975
	};
1976
1977
	/*
1978
	* Splits datetime string into date and time substrings.
1979
	* Throws exception when date can't be parsed
1980
	* Returns {dateString: dateString, timeString: timeString}
1981
	*/
1982
	var splitDateTime = function (dateTimeString, timeSettings) {
1983
		// The idea is to get the number separator occurrences in datetime and the time format requested (since time has
1984
		// fewer unknowns, mostly numbers and am/pm). We will use the time pattern to split.
1985
		var separator = computeEffectiveSetting(timeSettings, 'separator'),
1986
			format = computeEffectiveSetting(timeSettings, 'timeFormat'),
1987
			timeParts = format.split(separator), // how many occurrences of separator may be in our format?
1988
			timePartsLen = timeParts.length,
1989
			allParts = dateTimeString.split(separator),
1990
			allPartsLen = allParts.length;
1991
1992
		if (allPartsLen > 1) {
1993
			return {
1994
				dateString: allParts.splice(0, allPartsLen - timePartsLen).join(separator),
1995
				timeString: allParts.splice(0, timePartsLen).join(separator)
1996
			};
1997
		}
1998
1999
		return {
2000
			dateString: dateTimeString,
2001
			timeString: ''
2002
		};
2003
	};
2004
2005
	/*
2006
	* Internal function to parse datetime interval
2007
	* Returns: {date: Date, timeObj: Object}, where
2008
	*   date - parsed date without time (type Date)
2009
	*   timeObj = {hour: , minute: , second: , millisec: , microsec: } - parsed time. Optional
2010
	*/
2011
	var parseDateTimeInternal = function (dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings) {
2012
		var date,
2013
			parts,
2014
			parsedTime;
2015
2016
		parts = splitDateTime(dateTimeString, timeSettings);
2017
		date = $.datepicker._base_parseDate(dateFormat, parts.dateString, dateSettings);
2018
2019
		if (parts.timeString === '') {
2020
			return {
2021
				date: date
2022
			};
2023
		}
2024
2025
		parsedTime = $.datepicker.parseTime(timeFormat, parts.timeString, timeSettings);
2026
2027
		if (!parsedTime) {
2028
			throw 'Wrong time format';
2029
		}
2030
2031
		return {
2032
			date: date,
2033
			timeObj: parsedTime
2034
		};
2035
	};
2036
2037
	/*
2038
	* Internal function to set timezone_select to the local timezone
2039
	*/
2040
	var selectLocalTimezone = function (tp_inst, date) {
2041
		if (tp_inst && tp_inst.timezone_select) {
2042
			var now = date || new Date();
2043
			tp_inst.timezone_select.val(-now.getTimezoneOffset());
2044
		}
2045
	};
2046
2047
	/*
2048
	* Create a Singleton Instance
2049
	*/
2050
	$.timepicker = new Timepicker();
2051
2052
	/**
2053
	 * Get the timezone offset as string from a date object (eg '+0530' for UTC+5.5)
2054
	 * @param {number} tzMinutes if not a number, less than -720 (-1200), or greater than 840 (+1400) this value is returned
2055
	 * @param {boolean} iso8601 if true formats in accordance to iso8601 "+12:45"
2056
	 * @return {string}
2057
	 */
2058
	$.timepicker.timezoneOffsetString = function (tzMinutes, iso8601) {
2059
		if (isNaN(tzMinutes) || tzMinutes > 840 || tzMinutes < -720) {
2060
			return tzMinutes;
2061
		}
2062
2063
		var off = tzMinutes,
2064
			minutes = off % 60,
2065
			hours = (off - minutes) / 60,
2066
			iso = iso8601 ? ':' : '',
2067
			tz = (off >= 0 ? '+' : '-') + ('0' + Math.abs(hours)).slice(-2) + iso + ('0' + Math.abs(minutes)).slice(-2);
2068
2069
		if (tz === '+00:00') {
2070
			return 'Z';
2071
		}
2072
		return tz;
2073
	};
2074
2075
	/**
2076
	 * Get the number in minutes that represents a timezone string
2077
	 * @param  {string} tzString formatted like "+0500", "-1245", "Z"
2078
	 * @return {number} the offset minutes or the original string if it doesn't match expectations
2079
	 */
2080
	$.timepicker.timezoneOffsetNumber = function (tzString) {
2081
		var normalized = tzString.toString().replace(':', ''); // excuse any iso8601, end up with "+1245"
2082
2083
		if (normalized.toUpperCase() === 'Z') { // if iso8601 with Z, its 0 minute offset
2084
			return 0;
2085
		}
2086
2087
		if (!/^(\-|\+)\d{4}$/.test(normalized)) { // possibly a user defined tz, so just give it back
2088
			return parseInt(tzString, 10);
2089
		}
2090
2091
		return ((normalized.substr(0, 1) === '-' ? -1 : 1) * // plus or minus
2092
					((parseInt(normalized.substr(1, 2), 10) * 60) + // hours (converted to minutes)
2093
					parseInt(normalized.substr(3, 2), 10))); // minutes
2094
	};
2095
2096
	/**
2097
	 * No way to set timezone in js Date, so we must adjust the minutes to compensate. (think setDate, getDate)
2098
	 * @param  {Date} date
2099
	 * @param  {string} fromTimezone formatted like "+0500", "-1245"
2100
	 * @param  {string} toTimezone formatted like "+0500", "-1245"
2101
	 * @return {Date}
2102
	 */
2103
	$.timepicker.timezoneAdjust = function (date, fromTimezone, toTimezone) {
2104
		var fromTz = $.timepicker.timezoneOffsetNumber(fromTimezone);
2105
		var toTz = $.timepicker.timezoneOffsetNumber(toTimezone);
2106
		if (!isNaN(toTz)) {
2107
			date.setMinutes(date.getMinutes() + (-fromTz) - (-toTz));
2108
		}
2109
		return date;
2110
	};
2111
2112
	/**
2113
	 * Calls `timepicker()` on the `startTime` and `endTime` elements, and configures them to
2114
	 * enforce date range limits.
2115
	 * n.b. The input value must be correctly formatted (reformatting is not supported)
2116
	 * @param  {Element} startTime
2117
	 * @param  {Element} endTime
2118
	 * @param  {Object} options Options for the timepicker() call
2119
	 * @return {jQuery}
2120
	 */
2121
	$.timepicker.timeRange = function (startTime, endTime, options) {
2122
		return $.timepicker.handleRange('timepicker', startTime, endTime, options);
2123
	};
2124
2125
	/**
2126
	 * Calls `datetimepicker` on the `startTime` and `endTime` elements, and configures them to
2127
	 * enforce date range limits.
2128
	 * @param  {Element} startTime
2129
	 * @param  {Element} endTime
2130
	 * @param  {Object} options Options for the `timepicker()` call. Also supports `reformat`,
2131
	 *   a boolean value that can be used to reformat the input values to the `dateFormat`.
2132
	 * @param  {string} method Can be used to specify the type of picker to be added
0 ignored issues
show
Documentation introduced by
The parameter method does not exist. Did you maybe forget to remove this comment?
Loading history...
2133
	 * @return {jQuery}
2134
	 */
2135
	$.timepicker.datetimeRange = function (startTime, endTime, options) {
2136
		$.timepicker.handleRange('datetimepicker', startTime, endTime, options);
2137
	};
2138
2139
	/**
2140
	 * Calls `datepicker` on the `startTime` and `endTime` elements, and configures them to
2141
	 * enforce date range limits.
2142
	 * @param  {Element} startTime
2143
	 * @param  {Element} endTime
2144
	 * @param  {Object} options Options for the `timepicker()` call. Also supports `reformat`,
2145
	 *   a boolean value that can be used to reformat the input values to the `dateFormat`.
2146
	 * @return {jQuery}
2147
	 */
2148
	$.timepicker.dateRange = function (startTime, endTime, options) {
2149
		$.timepicker.handleRange('datepicker', startTime, endTime, options);
2150
	};
2151
2152
	/**
2153
	 * Calls `method` on the `startTime` and `endTime` elements, and configures them to
2154
	 * enforce date range limits.
2155
	 * @param  {string} method Can be used to specify the type of picker to be added
2156
	 * @param  {Element} startTime
2157
	 * @param  {Element} endTime
2158
	 * @param  {Object} options Options for the `timepicker()` call. Also supports `reformat`,
2159
	 *   a boolean value that can be used to reformat the input values to the `dateFormat`.
2160
	 * @return {jQuery}
2161
	 */
2162
	$.timepicker.handleRange = function (method, startTime, endTime, options) {
2163
		options = $.extend({}, {
2164
			minInterval: 0, // min allowed interval in milliseconds
2165
			maxInterval: 0, // max allowed interval in milliseconds
2166
			start: {},      // options for start picker
2167
			end: {}         // options for end picker
2168
		}, options);
2169
2170
		// for the mean time this fixes an issue with calling getDate with timepicker()
2171
		var timeOnly = false;
2172
		if(method === 'timepicker'){
2173
			timeOnly = true;
2174
			method = 'datetimepicker';
2175
		}
2176
2177
		function checkDates(changed, other) {
2178
			var startdt = startTime[method]('getDate'),
2179
				enddt = endTime[method]('getDate'),
2180
				changeddt = changed[method]('getDate');
2181
2182
			if (startdt !== null) {
2183
				var minDate = new Date(startdt.getTime()),
2184
					maxDate = new Date(startdt.getTime());
2185
2186
				minDate.setMilliseconds(minDate.getMilliseconds() + options.minInterval);
2187
				maxDate.setMilliseconds(maxDate.getMilliseconds() + options.maxInterval);
2188
2189
				if (options.minInterval > 0 && minDate > enddt) { // minInterval check
2190
					endTime[method]('setDate', minDate);
2191
				}
2192
				else if (options.maxInterval > 0 && maxDate < enddt) { // max interval check
2193
					endTime[method]('setDate', maxDate);
2194
				}
2195
				else if (startdt > enddt) {
2196
					other[method]('setDate', changeddt);
2197
				}
2198
			}
2199
		}
2200
2201
		function selected(changed, other, option) {
2202
			if (!changed.val()) {
2203
				return;
2204
			}
2205
			var date = changed[method].call(changed, 'getDate');
2206
			if (date !== null && options.minInterval > 0) {
2207
				if (option === 'minDate') {
2208
					date.setMilliseconds(date.getMilliseconds() + options.minInterval);
2209
				}
2210
				if (option === 'maxDate') {
2211
					date.setMilliseconds(date.getMilliseconds() - options.minInterval);
2212
				}
2213
			}
2214
2215
			if (date.getTime) {
2216
				other[method].call(other, 'option', option, date);
2217
			}
2218
		}
2219
2220
		$.fn[method].call(startTime, $.extend({
2221
			timeOnly: timeOnly,
2222
			onClose: function (dateText, inst) {
0 ignored issues
show
Unused Code introduced by
The parameter dateText is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter inst is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
2223
				checkDates($(this), endTime);
2224
			},
2225
			onSelect: function (selectedDateTime) {
0 ignored issues
show
Unused Code introduced by
The parameter selectedDateTime is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
2226
				selected($(this), endTime, 'minDate');
2227
			}
2228
		}, options, options.start));
2229
		$.fn[method].call(endTime, $.extend({
2230
			timeOnly: timeOnly,
2231
			onClose: function (dateText, inst) {
0 ignored issues
show
Unused Code introduced by
The parameter inst is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter dateText is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
2232
				checkDates($(this), startTime);
2233
			},
2234
			onSelect: function (selectedDateTime) {
0 ignored issues
show
Unused Code introduced by
The parameter selectedDateTime is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
2235
				selected($(this), startTime, 'maxDate');
2236
			}
2237
		}, options, options.end));
2238
2239
		checkDates(startTime, endTime);
2240
2241
		selected(startTime, endTime, 'minDate');
2242
		selected(endTime, startTime, 'maxDate');
2243
2244
		return $([startTime.get(0), endTime.get(0)]);
2245
	};
2246
2247
	/**
2248
	 * Log error or data to the console during error or debugging
2249
	 * @param  {Object} err pass any type object to log to the console during error or debugging
0 ignored issues
show
Documentation introduced by
The parameter err does not exist. Did you maybe forget to remove this comment?
Loading history...
2250
	 * @return {void}
2251
	 */
2252
	$.timepicker.log = function () {
2253
		// Older IE (9, maybe 10) throw error on accessing `window.console.log.apply`, so check first.
2254
		if (window.console && window.console.log && window.console.log.apply) {
2255
			window.console.log.apply(window.console, Array.prototype.slice.call(arguments));
2256
		}
2257
	};
2258
2259
	/*
2260
	 * Add util object to allow access to private methods for testability.
2261
	 */
2262
	$.timepicker._util = {
2263
		_extendRemove: extendRemove,
2264
		_isEmptyObject: isEmptyObject,
2265
		_convert24to12: convert24to12,
2266
		_detectSupport: detectSupport,
2267
		_selectLocalTimezone: selectLocalTimezone,
2268
		_computeEffectiveSetting: computeEffectiveSetting,
2269
		_splitDateTime: splitDateTime,
2270
		_parseDateTimeInternal: parseDateTimeInternal
2271
	};
2272
2273
	/*
2274
	* Microsecond support
2275
	*/
2276
	if (!Date.prototype.getMicroseconds) {
2277
		Date.prototype.microseconds = 0;
0 ignored issues
show
Compatibility Best Practice introduced by
You are extending the built-in type Date. This may have unintended consequences on other objects using this built-in type. Consider subclassing instead.
Loading history...
2278
		Date.prototype.getMicroseconds = function () { return this.microseconds; };
0 ignored issues
show
Compatibility Best Practice introduced by
You are extending the built-in type Date. This may have unintended consequences on other objects using this built-in type. Consider subclassing instead.
Loading history...
2279
		Date.prototype.setMicroseconds = function (m) {
0 ignored issues
show
Compatibility Best Practice introduced by
You are extending the built-in type Date. This may have unintended consequences on other objects using this built-in type. Consider subclassing instead.
Loading history...
2280
			this.setMilliseconds(this.getMilliseconds() + Math.floor(m / 1000));
2281
			this.microseconds = m % 1000;
2282
			return this;
2283
		};
2284
	}
2285
2286
	/*
2287
	* Keep up with the version
2288
	*/
2289
	$.timepicker.version = "1.6.3";
2290
2291
}));
2292